const PAUSED = 1;
const PLAYING = 2;
const REVERSING = 3;

/**
 * 渐变引擎类
 */
export default class TweenEngine {
  constructor(tweenFunc, easingFunc, begin, finish, duration, infinite, yoyo) {
    // 渐变函数
    this.tweenFunc = tweenFunc;
    // 缓动函数
    this.easingFunc = easingFunc;
    this.begin = begin;
    // 持续时间
    this.duration = duration;
    // 无限次播放
    this.infinite = infinite;
    // 无限次正反播放
    this.yoyo = yoyo;
    this.pos = begin;
    this.prevPos = 0;
    this.time = 0;
    this.startTime = 0;
    this.change = finish - begin;
    this.pause();
  }
  fire(method) {
    this[method]?.();
  }
  setTime(t) {
    if (t > this.duration) {
      if (this.yoyo) {
        this.time = this.duration;
        this.reverse();
      } else if (this.infinite) {
        this.time = 0;
        this.play();
      } else {
        this.finish();
      }
    } else if (t < 0) {
      if (this.yoyo) {
        this.time = 0;
        this.play();
      } else if (this.infinite) {
        this.time = this.duration;
        this.reverse();
      } else {
        this.reset();
      }
    } else {
      this.time = t;
      this.update();
    }
  }
  getTime() {
    return this.time;
  }
  setPosition(p) {
    this.prevPos = this.pos;
    this.tweenFunc(p);
    this.pos = p;
  }
  getPosition(t) {
    if (t === undefined) t = this.time;
    return this.easingFunc(t, this.begin, this.change, this.duration);
  }
  play() {
    this.state = PLAYING;
    this.startTime = this.getTimer() - this.time;
    this.onEnterFrame();
    this.fire('onPlay');
  }
  reverse() {
    this.state = REVERSING;
    this.time = this.duration - this.time;
    this.startTime = this.getTimer() - this.time;
    this.onEnterFrame();
    this.fire('onReverse');
  }
  seek(t) {
    this.pause();
    this.time = t;
    this.update();
    this.fire('onSeek');
  }
  reset() {
    this.pause();
    this.time = 0;
    this.update();
    this.fire('onReset');
  }
  finish() {
    this.pause();
    this.time = this.duration;
    this.update();
    this.fire('onFinish');
  }
  update() {
    this.setPosition(this.getPosition(this.time));
    this.fire('onUpdate');
  }
  onEnterFrame() {
    const t = this.getTimer() - this.startTime;
    if (this.state === PLAYING) {
      this.setTime(t);
    } else if (this.state === REVERSING) {
      this.setTime(this.duration - t);
    }
  }
  pause() {
    this.state = PAUSED;
    this.fire('onPause');
  }
  getTimer() {
    return new Date().getTime();
  }
  onPlay() {}
  onReverse() {}
  onPause() {}
  onFinish() {}
  onReset() {}
  onUpdate() {}
}
